#!/usr/bin/env perl -w
# Time-stamp: <25 May 00 10:34:42 giron1>

=head1 NAME

select.perl -  generates random prompts out of a list of prompts

=head1 SYNOPSIS

select.perl <listfile containing the prompts> <desired number>

=head1 DESCRIPTION

This programs generates random prompts out of a list of prompts

=head1 SEE ALSO


=head1 AUTHOR

 # $Id: select.perl,v 1.1 2007/10/08 09:26:05 schweitz Exp $
 Thomas Kemp

=head1 LOG

 $Log: select.perl,v $
 Revision 1.1  2007/10/08 09:26:05  schweitz
 version 2.4, lib vergessen

 Revision /main/2  22-Jan-2003.10:04:12  giron1
 Changing header to /usr/bin/env perl.
 
 Revision 1.1  2000/05/25 08:37:33  giron1
 Podified the program

 Revision 1.3  2000/02/14 15:04:09  kempt1
 Now auto-detection of probabilities in file works (replaced 0.0 by 1.0 for the compare)
 improved commandline args handling, now arguments may occur anywhere
 Now old syntax (<list> <n>) works again

 Revision 1.2  2000/02/10 14:42:28  kempt1
 now probabilities word. Added several flags.

 Revision 1.1  2000/01/28 09:01:28  kempt1
 Initial revision

=cut


$has_probabilities = "unknown";
$no_repetitions = 0;
$numToken = -1;

srand( time() ^ ($$ + ($$ << 15)) );

if ($#ARGV < 0) { print STDERR "Usage: <this script> <file>, specify -h for help\n"; exit; }


$arglist = "";
ARG:
while ($#ARGV > -1) {
  $thisflag = shift(@ARGV);
  if ($thisflag eq "-h") { &usage; exit; }
  if ($thisflag eq "-raw") { $has_probabilities = "no"; next ARG; }
  if ($thisflag eq "-s") { srand(shift @ARGV); next ARG; }
  if ($thisflag eq "-n") { $numToken = shift(@ARGV); next ARG; }
  if ($thisflag eq "-u") { $no_repetitions = 1; next ARG; }
  if ($thisflag =~ /\-/) {
    print STDERR "Unknown flag $thisflag, use -h for help\n"; exit;
  } else {
    push(@arglist, $thisflag);
  }
}

# now @arglist contains all non-flags in order of appearance
if ($#arglist < 0) { &usage; exit; }
$file = shift(@arglist);
if ($#arglist > -1) { $numToken = shift(@arglist); }

# finished processing command line args

open(FP,$file) || die "Could not open $file!\n";

# file with probabilities
$lineN = 0;

if ($has_probabilities eq "unknown") {
  while (<FP>) {
    # canonicalize line: delete double space, space at beginning of line,
    # CR, and CRLF (windows style)
    s/\r//g; s/\n//g; y/ / /s; s/^ //;
    # scan for file structure
    @_ = split(/[\s]+/);
    if ($#_ > -1) {
      # ignore empty lines
      if ($#_ == 0) { $has_probabilities = "no"; goto NOPROB; }
      $item = "1" . $_[0];
      if ($item > 1.0) {} else { $has_probabilities = "no"; goto NOPROB; }
    }
  }
  $has_probabilities = "yes";
}

NOPROB:

$prob_mass = 0;
$lineN = 0;
seek FP,0,0;
while (<FP>) {
  # canonicalize line: delete double space, space at beginning of line,
  # CR, and CRLF (windows style)
  s/\r//g; s/\n//g; y/ / /s; s/^ //;
  @_ = split(/[\s]+/);
  if ($#_ > -1) {
    $lineN++;
    if ($has_probabilities eq "yes") {
      $likelihood[++$#likelihood] = $_[0];
      $prob_mass += $_[0];
      shift @_;
    } else {
      $likelihood[++$#likelihood] = 1.0;
      $prob_mass += 1.0;
    }
    $string[++$#string] = join " ",@_;
  }
}
close(FP);

# OK, now have it all in the arrays
if ($numToken < 0) { 
  $numToken = $#string + 1; 
}

for ($i=0; $i < $numToken; $i++) {
  if ($prob_mass == 0) { print STDERR "Probability mass zero - cannot output more\n"; exit; }
  $idx = rand ($prob_mass);
  $accumulated = 0.0; $t= -1;
  while ($accumulated < $idx) {
    $t++;
    $accumulated += $likelihood[$t];
  }
  print "$string[$t]\n";
  #
  if ($no_repetitions) {
    $prob_mass -= $likelihood[$t];
    if ($t == $#likelihood) { 
      $#likelihood--; $#string--;
    } else {
      $likelihood[$t] = pop(@likelihood);
      $string[$t] = pop(@string);
    }
  }


}

exit;


sub usage {
  warn "Usage: perl <this script> [-u] [-s <random seed>] [-raw] [-n <number>] <file>\n\n";
  warn " This script will print <number> lines randomly picked from file <file>\n";
  warn " <number> is the number of lines in <file> if not specified.\n";
  warn " By default, the likelihood of each of the lines is identical for all lines.\n";
  warn " If, however, each line in the file begins with a number (numerical\n";
  warn "  expression), this number is assumed to be the likelihood of the line\n";
  warn "  and the line will be selected according to its likelihood. Zero likelihood\n";
  warn "  is allowed and will result in this line being never selected.\n";
  warn "  The likelihood need not add to one; it is automatically scaled.\n";
  warn "  Therefore, it is perfectly okay to put counts there.\n";
  warn " -raw will force the treatment of each line being equally likely, even\n";
  warn "  if there are numbers leading each line. If -raw is specified, and there\n";
  warn "  are numbers in each line, the numbers will be printed just like ordinary text.\n";
  warn " -u means unique mode and will cause each line to be printed (at most) once\n";
  warn " By specifying a random number seed with -s, deterministic behaviour\n";
  warn "  (deterministic randomness) can be accomplished.\n";
  return 0;
}
